`ifndef MY_MONITOR_SVH
`define MY_MONITOR_SVH
typedef class my_transaction;

class my_monitor extends uvm_monitor;

    virtual my_if vif;
    uvm_analysis_port #(my_transaction) ap;
    `uvm_component_utils(my_monitor)
    function new(string name = "my_monitor", uvm_component parent = null);
        super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ap = new("ap", this);
        if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
            `uvm_fatal("my_monitor", "virtual interface must be set for vif")
    endfunction

    extern task main_phase(uvm_phase phase);
    extern task collect_one_pkt(my_transaction tr); 
endclass

task my_monitor::main_phase(uvm_phase phase);
    my_transaction tr;
    while(1)begin
        tr = new("tr");
        collect_one_pkt(tr);
        ap.write(tr);
    end
endtask

task my_monitor::collect_one_pkt(my_transaction tr);
`ifdef USER_UVM_FIELD_AUTOMATION_PACK_TEST
    int data_size;
    bit [7:0] data_array[];
`else
    int psize;
`endif
    bit [7:0] data_q[$];
    while(1) begin
        @(posedge vif.clk);
        if(vif.valid == 1)
            break;
    end
    `uvm_info("my_monitor", "begin to collect one pkt", UVM_LOW)
    while(vif.valid)begin
        data_q.push_back(vif.data);
        @(posedge vif.clk);
    end
`ifdef USER_UVM_FIELD_AUTOMATION_PACK_TEST
    data_size = data_q.size();
    `uvm_info(this.get_type_name(), $sformatf("unpacked byte number is %0d", data_size), UVM_LOW);
    data_array = new[data_size];
    for(int i = 0; i < data_size; i++)begin
        data_array[i] = data_q[i];
    end
    tr.pload = new[data_size - 22];
    data_size = tr.unpack_bytes(data_array) / 8;
`else
    // pop dmac
    for(int i = 0; i < 6; i++)begin
        tr.dmac = {data_q.pop_front(), tr.dmac[47:8]};
    end
    // pop smac
    for(int i = 0; i < 6; i++)begin
        tr.smac = {data_q.pop_front(), tr.smac[47:8]};
    end
    // pop ether_type
    for(int i = 0; i < 2; i++)begin
        tr.ether_type = {data_q.pop_front(), tr.ether_type[15:8]};
    end
    // pop payload
    psize = data_q.size();
    //tr.pload.delete();
    tr.pload = new[psize - 4];
    for(int i = 0; i < psize - 4; i++)begin
       //tr.pload = new[tr.pload.size() + 1](tr.pload);
        tr.pload[i] = data_q.pop_front();
    end
    // pop crc
    for(int i = 0; i < 4; i++)begin
        tr.crc = {data_q.pop_front(), tr.crc[31:8]};
    end
`endif
    `uvm_info("my_monitor", "end to collect one pkt", UVM_LOW)
    // filed automation can replace <my_print>
    //tr.my_print();
    tr.print();
endtask
`endif
